package utils.common;

import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;

import java.util.*;

/**
 * <h1>参数集合</h1>
 *
 * @author Zhou Yifan
 */
public class ArgumentSet {

    /**
     * 参数数组
     */
    private ArgEntry[] args;

    /**
     * 参数前缀集合
     */
    private Map<String, ArgEntry> prefixArgs = new HashMap<>();

    /**
     * 参数选项集合
     */
    private Set<String> options = new HashSet<>();

    private ArgumentSet(ArgEntry @NotNull [] args) {
        this.args = args;
        for (ArgEntry arg : args) {
            if (arg.prefix != null) {
                prefixArgs.put(arg.prefix, arg);
            }
            if (arg.option != null) {
                options.add(arg.option);
            }
        }
    }

    /**
     * 判断当前参数集合是否包含某个选项
     *
     * @param option 选项
     * @return 布尔值
     */
    public boolean hasOption(String option) {
        return options.contains(option);
    }

    /**
     * 判断在指定参数数组中是否有某个 option
     *
     * @param args   指定参数数组
     * @param option 选项
     * @return 布尔值
     */
    public static boolean hasOption(String[] args, String option) {
        boolean contains = false;
        if (args != null) {
            for (String a : args) {
                if (option.equalsIgnoreCase(a)) {
                    contains = true;
                    break;
                }
            }
        }
        return contains;
    }

    /**
     * 获取一个新的设置对象
     *
     * @return {@link Setting}
     */
    @Contract(" -> new")
    public static @NotNull Setting setting() {
        return new Setting();
    }

    @Contract("null, _ -> new")
    public static @NotNull ArgumentSet resolve(String[] args, Setting setting) {
        if (args == null) {
            return new ArgumentSet(new ArgEntry[0]);
        }
        List<ArgEntry> argEntries = new ArrayList<>();
        for (int i = 0; i < args.length; i++) {
            if (setting.prefixes.contains(args[i])) {
                ArgEntry argEntry = new ArgEntry();
                argEntry.prefix = args[i];
                if (i + 1 >= args.length) {
                    throw new IllegalArgumentException(String.format("Missing %s parameter!", args[i]));
                }
                i++;
                argEntry.value = args[i];
                argEntries.add(argEntry);
                continue;
            }
            if (setting.options.contains(args[i])) {
                ArgEntry argEntry = new ArgEntry();
                argEntry.option = args[i];
                argEntries.add(argEntry);
            }
        }
        int n = argEntries.size();
        return new ArgumentSet(argEntries.toArray(new ArgEntry[n]));
    }

    public ArgEntry[] getArgs() {
        return args;
    }

    public ArgEntry getArg(String prefix) {
        return prefixArgs.get(prefix);
    }

    /**
     * 参数体
     */
    public static class ArgEntry {
        private String prefix;
        private String value;
        private String option;

        public String getPrefix() {
            return prefix;
        }

        public String getValue() {
            return value;
        }

        public String getOption() {
            return option;
        }
    }

    /**
     * 设置项
     */
    public static class Setting {
        private Set<String> prefixes = new HashSet<>();
        private Set<String> options = new HashSet<>();

        private Setting() {
        }

        public Setting prefix(String... prefixes) {
            this.prefixes.addAll(Arrays.asList(prefixes));
            return this;
        }

        public Setting option(String... options) {
            this.options.addAll(Arrays.asList(options));
            return this;
        }
    }
}
